package com.atguigu.service.impl;

import com.atguigu.client.ProductFeignClient;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.CartInfo;
import com.atguigu.entity.SkuInfo;
import com.atguigu.mapper.CartInfoMapper;
import com.atguigu.service.AsyncCartInfoService;
import com.atguigu.service.CartInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车表 用户登录系统时更新冗余 服务实现类
 * </p>
 *
 * @author zhangqiang
 * @since 2021-09-04
 */
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private AsyncCartInfoService asyncCartInfoService;

    public void addTOCart(String userId,Long skuId,Integer skuNum){
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("sku_id", skuId);
        CartInfo exisCartInfo = baseMapper.selectOne(wrapper);
        if (exisCartInfo!=null){
            exisCartInfo.setSkuNum(exisCartInfo.getSkuNum()+skuNum);

            baseMapper.updateById(exisCartInfo);
        }else{
            exisCartInfo=new CartInfo();
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            exisCartInfo.setUserId(userId);
            exisCartInfo.setSkuId(skuId);
        }
    }

    @Override
    public List<CartInfo> getSelectedProduct(String userId) {
        ArrayList<CartInfo> retCartInfoList = new ArrayList<>();
        String cartKey = getCartKey(userId);
        //拿到该用户所对应的所有购物车信息
        List<CartInfo> redisCartInfoList = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(redisCartInfoList)){
            for (CartInfo cartInfo : redisCartInfoList) {
                //拿到购物车选择信息
                if (cartInfo.getIsChecked()==1){
                    retCartInfoList.add(cartInfo);
                }
            }
        }
        return retCartInfoList;
    }

    @Override
    public void deleteCart(String userId, Long skuId) {
        //a.在数据库里面删除购物车信息
        asyncCartInfoService.deleteCartInfo(userId,skuId);
        //操作redis删除里面的的对于商品
        String cartKey = getCartKey(userId);
        BoundHashOperations operations = redisTemplate.boundHashOps(cartKey);
        if (operations.hasKey(skuId.toString())){
            //删除数据
            operations.delete(skuId.toString());
        }
    }

    @Override
    public void checkCart(String userId, Long skuId, Integer isChecked) {
        //1.在数据库里面需要修改选中或者未选中状态
        asyncCartInfoService.checkCart(userId,skuId,isChecked);
        //操作redis的选中状态
        String cartKey = getCartKey(userId);
        BoundHashOperations operations = redisTemplate.boundHashOps(cartKey);
        if(operations.hasKey(skuId.toString())){
            //从redis里面拿取到购物车的信息
            CartInfo redisCartInfo =(CartInfo) operations.get(skuId.toString());
            redisCartInfo.setIsChecked(isChecked);
            //更新到redis内
            //TODO
            operations.put(skuId.toString(), redisCartInfo);
            setCartKeyExpire(cartKey);
        }
    }

    @Override
    public List<CartInfo> getCartList(String userId,String userTempId){
        List<CartInfo> cartInfoList=new ArrayList<>();
        //当用户没有登陆的时候
        if (StringUtils.isEmpty(userId)){
            cartInfoList=getUserCartList(userTempId);
        }
        //用户已登陆
        if (!StringUtils.isEmpty(userId)){
            //先查询未登陆的购物车信息,合并
            List<CartInfo> noLoginCartInfoList = getUserCartList(userTempId);
            if (!CollectionUtils.isEmpty(noLoginCartInfoList)) {
                //合并购物车信息
                cartInfoList = mergeCartList(noLoginCartInfoList, userId);
                //合并之后删除临时购物车信息
                deleteNoLoginCartInfoList(userTempId);
            }
            //如果noLoginCartInfoList为空 未登录情况没有商品加入购物车/已经被合并
            if (CollectionUtils.isEmpty(noLoginCartInfoList)) {
                cartInfoList = queryFromDbToRedis(userId);
            }
        }
        return cartInfoList;
    }

    //删除未登录的信息
    private void deleteNoLoginCartInfoList(String userTempId) {
        asyncCartInfoService.deleteCartInfo(userTempId, null);
        //删除redis
        String cartKey = getCartKey(userTempId);
        Boolean aBoolean = redisTemplate.hasKey(cartKey);
        if (aBoolean){
            redisTemplate.delete(cartKey);
        }
    }

    private List<CartInfo> getUserCartList(String oneOfUserId) {
        List<CartInfo> cartInfoList=new ArrayList<>();
        //如果临时用户id也为空
        if (StringUtils.isEmpty(oneOfUserId)){
            return cartInfoList;
        }
        cartInfoList=queryFromDbToRedis(oneOfUserId);
        return cartInfoList;
    }
private List<CartInfo> mergeCartList(List<CartInfo> npLogoinCartInfoList,String userId){
        //取出登陆和未登录的购物车信息
         List<CartInfo> loginCartInfoList = getUserCartList(userId);
        //b.对比sku的id是否相同--把其中一个集合转换为一个map key:skuId value:cartInfo
            Map<Long, CartInfo> loginCartInfoMap = loginCartInfoList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
            for (CartInfo noLoginCartInfo : npLogoinCartInfoList) {
                Long skuId = noLoginCartInfo.getSkuId();
                if (loginCartInfoMap.containsKey(skuId)) {
                //判断skuId是否相同
                CartInfo loginCartInfo = loginCartInfoMap.get(skuId);
                loginCartInfo.setSkuNum(loginCartInfo.getSkuNum() + noLoginCartInfo.getSkuNum());
                    //当未登录的时候如果商品是勾选状态 合并之后也要勾选
                    if (noLoginCartInfo.getIsChecked() == 1) {
                        loginCartInfo.setIsChecked(1);
                    }
                    baseMapper.updateById(loginCartInfo);
                }else {
                    //把临时用户id改为已登录用户id
                    noLoginCartInfo.setUserId(userId);
                    baseMapper.updateById(noLoginCartInfo);
                }
            }
            //合并之后需要更新下缓存
    //合并之后需要更新一下缓存
    List<CartInfo> cartInfoList = queryFromDbToRedis(userId);
    return cartInfoList;

}

    @Override
    public List<CartInfo> queryFromDbToRedis(String oneOfUserId) {
        //根据用户id查询购物车信息
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", oneOfUserId);
        List<CartInfo> dbCartInfoList = baseMapper.selectList(wrapper);
        //如果数据库中不存在用户添加的购物车信息
        if (CollectionUtils.isEmpty(dbCartInfoList)){
            return dbCartInfoList;
        }
        //如果有购物车数据放到redis当中
        String cartKey = getCartKey(oneOfUserId);
        Map<String, CartInfo> cartInfoMap = new HashMap<>();
        for (CartInfo cartInfo : dbCartInfoList) {
            //方式一单个添加,效率低
            //redisTemplate.opsForHash().put(cartKey,cartInfo.getSkuId().toString(),cartInfo);
            //随着时间的推移 商品价格有可能变化 此时需要更新商品实时价格
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            cartInfoMap.put(cartInfo.getSkuId().toString(), cartInfo);
        }
        //方式二:批量添加
        redisTemplate.opsForHash().putAll(cartKey, cartInfoMap);
        //设置购物车过期时间
        setCartKeyExpire(cartKey);
        return dbCartInfoList;
    }

    @Override
    public void addToCart(String userId, Long skuId, Integer skuNum) {
        //查询数据库是否有购物车信息
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("sku_id", skuId);
        CartInfo existCartInfo = baseMapper.selectOne(wrapper);
        //有
        if (existCartInfo != null){
            //商品数量总和
            existCartInfo.setSkuNum(existCartInfo.getSkuNum() + skuNum);
            //更新购物车实时价格
            existCartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
            //更新购物车数据库
            asyncCartInfoService.updateCartInfo(existCartInfo);
        }else {
            existCartInfo = new CartInfo();
            //先查询skuInfo的信息
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            existCartInfo.setUserId(userId);
            existCartInfo.setSkuId(skuId);
            //添加购物车的时候的价格
            existCartInfo.setCartPrice(skuInfo.getPrice());
            existCartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            existCartInfo.setSkuName(skuInfo.getSkuName());
            existCartInfo.setSkuNum(skuNum);
            existCartInfo.setIsChecked(1);
            //添加购物车的时候的价格
            existCartInfo.setRealTimePrice(skuInfo.getPrice());
            //baseMapper.insert(existCartInfo);
            asyncCartInfoService.saveCartInfo(existCartInfo);
        }
        //redis存储一份提高查询效率
        String cartKey = getCartKey(userId);
        //设置购物车过期时间
        setCartKeyExpire(cartKey);
    }
    //购物车的信息是需要过期时间
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }
    //获取购物车的key信息
    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }
}



















